
package nsga;

public class CamionVRPTW implements Cloneable
{
    private int numeroCamion;
    private ClienteVRPTW[] clientes;
    private double[][] tiempos;
    private double capacity;
    private int length;
    private double[] tiempoActual;
    private int[] orden;
    private int n;//Cantidad de Ciudades atendidas
    private int[] atendidos;
    private int cantidadDigitos;
    private boolean fin;

    public CamionVRPTW(int numeroCamion, ClienteVRPTW[] clientes, double[][] tiempos, double capacity, double tiempoInicio, int[] atendidos)
    {
        this.numeroCamion=numeroCamion;
        this.clientes=clientes;
        this.tiempos=tiempos;
        this.capacity=capacity;
        length=this.clientes.length;
        tiempoActual=new double[length];
        tiempoActual[0]=tiempoInicio;
        orden=new int[length];
        orden[0]=0;
        n=1;
        this.atendidos=atendidos;
        fin=false;
        cantidadDigitos=(int)Math.pow(10, String.valueOf(length).length());
    }
    
    public static boolean allClientesTested(int[] probados)
    {
        for(int i=1;i<probados.length;i++)
        {
            if(probados[i]==-1)
            {
                return false;
            }
        }
        return true;
    }
    
    private void addCliente()
    {
        int[] probados=atendidos.clone();
        do
        {
            int rand;
            do
            {
                rand=(int)(Math.random()*cantidadDigitos);
            }
            while(rand>=length);
            if(probados[rand]==-1)
            {
                if(((rand==0)&&allClientesTested(probados))||(rand>0))
                {
                    if(capacity<clientes[rand].getDemanda())
                    {
                        if(rand==0)
                        {
                            break;
                        }
                        else
                        {
                            probados[rand]=-2;
                        }
                    }
                    else
                    {
                        if(!((tiempoActual[(n-1)]+tiempos[orden[(n-1)]][rand])>clientes[rand].getTiempoApertura()))
                        {
                            if((clientes[rand].getTiempoApertura()+clientes[rand].getTiempoServicio())>clientes[rand].getTiempoCierre())
                            {
                                if(rand==0)
                                {
                                    break;
                                }
                                else
                                {
                                    probados[rand]=-2;
                                }
                            }
                            else
                            {
                                capacity-=clientes[rand].getDemanda();
                                tiempoActual[n]=clientes[rand].getTiempoApertura()+clientes[rand].getTiempoServicio();
                                if(rand==0)
                                {
                                    fin=true;
                                    break;
                                }
                                else
                                {
                                    atendidos[rand]=numeroCamion;
                                    orden[n]=rand;
                                    n++;
                                    addCliente();
                                    if(fin==true)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        capacity+=clientes[rand].getDemanda();
                                        n--;
                                        atendidos[rand]=-1;
                                        probados[rand]=-2;
                                    }
                                }
                            }
                        }
                        else
                        {
                            if((tiempoActual[(n-1)]+tiempos[orden[(n-1)]][rand]+clientes[rand].getTiempoServicio())>clientes[rand].getTiempoCierre())
                            {
                                if(rand==0)
                                {
                                    break;
                                }
                                else
                                {
                                    probados[rand]=-2;
                                }
                            }
                            else
                            {
                                capacity-=clientes[rand].getDemanda();
                                tiempoActual[n]=tiempoActual[(n-1)]+tiempos[orden[(n-1)]][rand]+clientes[rand].getTiempoServicio();
                                if(rand==0)
                                {
                                    fin=true;
                                    break;
                                }
                                else
                                {
                                    atendidos[rand]=numeroCamion;
                                    orden[n]=rand;
                                    n++;
                                    addCliente();
                                    if(fin==true)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        capacity+=clientes[rand].getDemanda();
                                        n--;
                                        atendidos[rand]=-1;
                                        probados[rand]=-2;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        while(true);
    }
    
    public static CamionVRPTW getCamionVRPTWGeneradoAleatoriamente(int numeroCamion, ClienteVRPTW[] clientes, double[][] tiempos, double capacity, double tiempoInicio, int[] atendidos)
    {
        CamionVRPTW camionVRPTW=new CamionVRPTW(numeroCamion, clientes, tiempos, capacity, tiempoInicio, atendidos);
        camionVRPTW.addCliente();
        return camionVRPTW;
    }
    
    public boolean addCliente(int cliente)
    {
        if(atendidos[cliente]!=-1)
        {
            return false;
        }
        else
        {
            if(capacity<clientes[cliente].getDemanda())
            {
                return false;
            }
            else
            {
                if(!((tiempoActual[(n-1)]+tiempos[orden[(n-1)]][cliente])>clientes[cliente].getTiempoApertura()))
                {
                    if((clientes[cliente].getTiempoApertura()+clientes[cliente].getTiempoServicio())>clientes[cliente].getTiempoCierre())
                    {
                        return false;
                    }
                    else
                    {
                        capacity-=clientes[cliente].getDemanda();
                        tiempoActual[n]=clientes[cliente].getTiempoApertura()+clientes[cliente].getTiempoServicio();
                        if(cliente==0)
                        {
                            fin=true;
                        }
                        else
                        {
                            atendidos[cliente]=numeroCamion;
                            orden[n]=cliente;
                            n++;
                        }
                        return true;
                    }
                }
                else
                {
                    if((tiempoActual[(n-1)]+tiempos[orden[(n-1)]][cliente]+clientes[cliente].getTiempoServicio())>clientes[cliente].getTiempoCierre())
                    {
                        return false;
                    }
                    else
                    {
                        capacity-=clientes[cliente].getDemanda();
                        tiempoActual[n]=tiempoActual[(n-1)]+tiempos[orden[(n-1)]][cliente]+clientes[cliente].getTiempoServicio();
                        if(cliente==0)
                        {
                            fin=true;
                        }
                        else
                        {
                            atendidos[cliente]=numeroCamion;
                            orden[n]=cliente;
                            n++;
                        }
                        return true;
                    }
                }
            }
        }
    }
    
    public void deleteCliente()
    {
        if(fin==true)
        {
            capacity+=clientes[0].getDemanda();
            fin=false;
        }
        else
        {
            n--;
            capacity+=clientes[orden[n]].getDemanda();
            atendidos[orden[n]]=-1;
        }
    }
    
    public int getCantidadCiudades()
    {
        return n-1;
    }
    
    public int[] getOrden()
    {
        int[] result=new int[n];
        for(int i=0;i<n;i++)
        {
            result[i]=orden[i];
        }
        return result;
    }
    
    public double getFitness()
    {
        double fitness=0;
        for(int i=0;i<(n-1);i++)
        {
            fitness+=tiempos[orden[i]][orden[(i+1)]];
        }
        fitness+=tiempos[orden[(n-1)]][orden[0]];
        return fitness;
    }

    public CamionVRPTW clone(int numeroCamion, int[] atendidos)
    {
        CamionVRPTW camionVRPTW=null;
        try
        {
            camionVRPTW=(CamionVRPTW)super.clone();
        }
        catch(CloneNotSupportedException cloneNotSupportedException)
        {
        }
        camionVRPTW.numeroCamion=numeroCamion;
        for(int i=1;i<camionVRPTW.n;i++)
        {
            atendidos[camionVRPTW.orden[i]]=camionVRPTW.numeroCamion;
        }
        camionVRPTW.atendidos=atendidos;
        camionVRPTW.orden=orden.clone();
        camionVRPTW.tiempoActual=tiempoActual.clone();
        return camionVRPTW;
    }
    
    public CamionVRPTW clone()
    {
        CamionVRPTW camionVRPTW=null;
        try
        {
            camionVRPTW=(CamionVRPTW)super.clone();
        }
        catch(CloneNotSupportedException cloneNotSupportedException)
        {
        }
        camionVRPTW.orden=orden.clone();
        camionVRPTW.atendidos=atendidos.clone();
        camionVRPTW.tiempoActual=tiempoActual.clone();
        return camionVRPTW;
    }
    
}
